package com.example.imgcompress.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Iterator;
import java.util.UUID;

@Service
public class ImageCompressService {

    @Value("${image.compress.max-width}")
    private int maxWidth;

    @Value("${image.compress.max-height}")
    private int maxHeight;

    @Value("${image.compress.quality}")
    private float quality;

    @Value("${image.compress.output-format}")
    private String outputFormat;

    @Value("${image.compress.max-file-size}")
    private long maxFileSize;

    @Value("${upload.path}")
    private String uploadPath;

    /**
     * 压缩图片
     */
    public CompressResult compressImage(MultipartFile file) throws IOException {
        // 验证文件
        validateFile(file);
        
        // 读取原始图片
        BufferedImage originalImage = ImageIO.read(file.getInputStream());
        if (originalImage == null) {
            throw new IllegalArgumentException("无法读取图片文件");
        }

        // 获取原始尺寸
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();

        // 计算新尺寸
        Dimension newDimension = calculateNewDimension(originalWidth, originalHeight);
        int newWidth = (int) newDimension.getWidth();
        int newHeight = (int) newDimension.getHeight();

        // 调整图片尺寸
        BufferedImage resizedImage = resizeImage(originalImage, newWidth, newHeight);

        // 压缩图片质量
        byte[] compressedBytes = compressImageQuality(resizedImage);

        // 保存压缩后的图片
        String fileName = generateFileName(file.getOriginalFilename());
        Path filePath = Paths.get(uploadPath, fileName);
        Files.createDirectories(filePath.getParent());
        Files.write(filePath, compressedBytes);

        // 返回结果
        return CompressResult.builder()
                .originalSize(file.getSize())
                .compressedSize(compressedBytes.length)
                .originalWidth(originalWidth)
                .originalHeight(originalHeight)
                .newWidth(newWidth)
                .newHeight(newHeight)
                .compressionRatio((double) compressedBytes.length / file.getSize())
                .fileName(fileName)
                .filePath(filePath.toString())
                .build();
    }

    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件为空");
        }
        
        if (file.getSize() > maxFileSize) {
            throw new IllegalArgumentException("文件大小超过限制: " + (maxFileSize / 1024 / 1024) + "MB");
        }

        String contentType = file.getContentType();
        if (contentType == null || !contentType.startsWith("image/")) {
            throw new IllegalArgumentException("不支持的文件类型");
        }
    }

    /**
     * 计算新尺寸
     */
    private Dimension calculateNewDimension(int originalWidth, int originalHeight) {
        double scale = 1.0;
        
        if (originalWidth > maxWidth) {
            scale = Math.min(scale, (double) maxWidth / originalWidth);
        }
        
        if (originalHeight > maxHeight) {
            scale = Math.min(scale, (double) maxHeight / originalHeight);
        }

        int newWidth = (int) (originalWidth * scale);
        int newHeight = (int) (originalHeight * scale);

        return new Dimension(newWidth, newHeight);
    }

    /**
     * 调整图片尺寸
     */
    private BufferedImage resizeImage(BufferedImage originalImage, int newWidth, int newHeight) {
        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = resizedImage.createGraphics();
        
        // 设置高质量渲染
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
        g2d.dispose();
        
        return resizedImage;
    }

    /**
     * 压缩图片质量
     */
    private byte[] compressImageQuality(BufferedImage image) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
        
        Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(outputFormat);
        if (!writers.hasNext()) {
            throw new IOException("不支持的输出格式: " + outputFormat);
        }
        
        ImageWriter writer = writers.next();
        writer.setOutput(ios);
        
        ImageWriteParam param = writer.getDefaultWriteParam();
        if (param.canWriteCompressed()) {
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(quality);
        }
        
        writer.write(null, new IIOImage(image, null, null), param);
        
        writer.dispose();
        ios.close();
        
        return outputStream.toByteArray();
    }

    /**
     * 生成文件名
     */
    private String generateFileName(String originalFilename) {
        String extension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        return UUID.randomUUID().toString() + "." + outputFormat;
    }

    /**
     * 压缩结果类
     */
    public static class CompressResult {
        private long originalSize;
        private long compressedSize;
        private int originalWidth;
        private int originalHeight;
        private int newWidth;
        private int newHeight;
        private double compressionRatio;
        private String fileName;
        private String filePath;

        // Builder模式
        public static Builder builder() {
            return new Builder();
        }

        public static class Builder {
            private CompressResult result = new CompressResult();

            public Builder originalSize(long originalSize) {
                result.originalSize = originalSize;
                return this;
            }

            public Builder compressedSize(long compressedSize) {
                result.compressedSize = compressedSize;
                return this;
            }

            public Builder originalWidth(int originalWidth) {
                result.originalWidth = originalWidth;
                return this;
            }

            public Builder originalHeight(int originalHeight) {
                result.originalHeight = originalHeight;
                return this;
            }

            public Builder newWidth(int newWidth) {
                result.newWidth = newWidth;
                return this;
            }

            public Builder newHeight(int newHeight) {
                result.newHeight = newHeight;
                return this;
            }

            public Builder compressionRatio(double compressionRatio) {
                result.compressionRatio = compressionRatio;
                return this;
            }

            public Builder fileName(String fileName) {
                result.fileName = fileName;
                return this;
            }

            public Builder filePath(String filePath) {
                result.filePath = filePath;
                return this;
            }

            public CompressResult build() {
                return result;
            }
        }

        // Getters
        public long getOriginalSize() { return originalSize; }
        public long getCompressedSize() { return compressedSize; }
        public int getOriginalWidth() { return originalWidth; }
        public int getOriginalHeight() { return originalHeight; }
        public int getNewWidth() { return newWidth; }
        public int getNewHeight() { return newHeight; }
        public double getCompressionRatio() { return compressionRatio; }
        public String getFileName() { return fileName; }
        public String getFilePath() { return filePath; }
    }
} 